package xyz.lwm.lazycat.beans;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import xyz.lwm.lazycat.annotation.Bean;
import xyz.lwm.lazycat.annotation.BeanScan;
import xyz.lwm.lazycat.annotation.Configuration;
import xyz.lwm.lazycat.annotation.Import;
import xyz.lwm.lazycat.utility.CollectionUtil;
import xyz.lwm.lazycat.utility.It;
import xyz.lwm.lazycat.utility.reflect.ReflectUtil;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Map;

/**
 * 配置类加载
 *
 * @author lwm
 * @see Configuration
 */
@Slf4j
@AllArgsConstructor
class BeanDesignConfigurationLoader implements BeanDesignRegistryCustomizer {

    private final BeanDesign<?> configurationDesign;

    private final BeanDesignRegistryCustomizers registryCustomizers;

    @Override
    public void customize(BeanDesignRegistry beanRegistry) {
        It.of(configurationDesign).also(design -> {
            // bean scan
            if (design.getAnnotations().hasAnnotation(BeanScan.class)) {
                It.of(design.getAnnotations().getAnnotation(BeanScan.class))
                        .let(BeanScan::value).filter(CollectionUtil::isNotEmpty)
                        .also(packages -> registryCustomizers
                                .add(new BeanDesignScanLoader(packages, registryCustomizers)));
            }
            // bean import
            if (design.getAnnotations().hasAnnotation(Import.class)) {
                It.of(design.getAnnotations().getAnnotation(Import.class))
                        .let(Import::value)
                        .also(imports -> registryCustomizers
                                .add(new BeanDesignImportLoader(imports, design.getAnnotations(), registryCustomizers)));
            }

            // get public and not static methods
            Map<String, Method> methods = ReflectUtil.findDeclaredMethods(design.getType(), null,
                    m -> Modifier.isPublic(m.getModifiers()) && !Modifier.isStatic(m.getModifiers()),
                    Method::getName, BeanDesignConfigurationLoader.class + "#customize(" + design.getName() + ")");

            // resolve method to bean design
            methods.forEach((methodName, method) ->
                BeanDesignUtil.buildDesign(method, new Dependency(design.getType(), design.getName(), design.getType()))
                        .filter(d -> d.getAnnotations().hasAnnotation(Bean.class))
                        .also(beanRegistry::register)
            );
        });
    }


}
